package com.rede.didiok.rank.event.listener;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.TypeReference;
import com.rede.didiok.common.constant.conf.SysConf;
import com.rede.didiok.common.constant.global.Constants;
import com.rede.didiok.common.convert.AggEsDocConvert;
import com.rede.didiok.common.dto.admin.SystemConfigDto;
import com.rede.didiok.common.dto.rank.RankMemberDto;
import com.rede.didiok.common.dto.user.NoticeDto;
import com.rede.didiok.common.dto.user.UserDto;
import com.rede.didiok.common.enums.*;
import com.rede.didiok.common.exception.exceptionType.FeignException;
import com.rede.didiok.common.executor.AsyncService;
import com.rede.didiok.common.feign.AdminFeignClient;
import com.rede.didiok.common.feign.UserFeignClient;
import com.rede.didiok.common.holder.RequestHolder;
import com.rede.didiok.common.schema.AggEsDoc;
import com.rede.didiok.common.utils.R;
import com.rede.didiok.common.utils.StringUtils;
import com.rede.didiok.common.utils.admin.SystemConfigUtil;
import com.rede.didiok.common.utils.business.RabbitMqUtil;
import com.rede.didiok.rank.entity.RankMemberEntity;
import com.rede.didiok.rank.event.rankMemberEvent.*;
import com.rede.didiok.rank.service.RankMemberService;

/**
 * @author 遇见
 */
@Component
@Slf4j
public class RankMemberListener {
    /**
     * 用户服务
     */
    @Resource
    private UserFeignClient userFeignClient;

    /**
     * 管理员服务
     */
    @Resource
    private AdminFeignClient adminFeignClient;

    @Autowired
    private SystemConfigUtil systemConfigUtil;

    /**
     * 简易的mq邮件封装工具类
     */
    @Resource
    private RabbitMqUtil rabbitMqUtil;

    /**
     * 异步执行服务
     */
    @Resource
    private AsyncService asyncService;

//    /**
//     * 系统配置；服务
//     */
//    @Resource
//    private SystemConfigService systemConfigService;

    /**
     * 博客服务
     */
    @Resource
    private RankMemberService rankMemberService;
//
//    @Resource
//    private SubjectItemService subjectItemService;


    /**
     * todo 2021/12/14  通知服务调用
     */

    /**
     * 博客新增事件
     *
     * @param event
     */
    @EventListener(value = RankMemberAddEvent.class)
    public void add(RankMemberEvent event) {
        RankMemberEntity rankMember = (RankMemberEntity) event.getSource();
        /**
         * 新增情况下 审核通过  说明是免审
         * 一般都不会走这一层
         * 博主属于特殊角色
         * 在新增博客选择发布时需要给与积分
         */
        if (AuditStatusEnum.AGREE.equals(rankMember.getAuditStatus()) && PublishEnum.PUBLISH.equals(rankMember.getIsPublish())) {
            /**
             * 站内信通知
             */
            this.sendNotice(rankMember);
        }

        /**
         * 新增时候选择发布的博客都给与网站管理员发送邮件提示
         */
        if (PublishEnum.PUBLISH.equals(rankMember.getIsPublish())) {
            /**
             * 通知运营
             */
            this.sendEmailToManager(rankMember);
        }

        //发布后台系统消息通知
        if (!AuditStatusEnum.AGREE.equals(rankMember.getAuditStatus()) || !PublishEnum.PUBLISH.equals(rankMember.getIsPublish())) {
            this.sendBlackNotice(rankMember);
        }

        // 更新索引
        this.syncAggEsDoc(rankMember, OperateEnum.ADD);
    }

    /**
     * 博客修改事件
     *
     * @param event
     */
    @EventListener(value = RankMemberEditEvent.class)
    public void edit(RankMemberEvent event) {
        RankMemberEntity rankMember = (RankMemberEntity) event.getSource();

        // 更新索引
        this.syncAggEsDoc(rankMember, OperateEnum.EDIT);
    }

    /**
     * 博客审核事件
     *
     * @param event
     */
    @EventListener(value = RankMemberAuditEvent.class)
    public void audit(RankMemberEvent event) {
        RankMemberEntity rankMember = (RankMemberEntity) event.getSource();
        if (PublishEnum.PUBLISH.equals(rankMember.getIsPublish()) && AuditStatusEnum.AGREE.equals(rankMember.getAuditStatus())) {
            /**
             * 站内信
             */
            this.sendNotice(rankMember);

            /**
             * 更新专栏，目前只开放运营添加专栏
             */
//            if (event.isAdmin()) {
//                this.upsertSubject(rankMember);
//            }
        }

        /**
         * 对作者发送邮件和站内信
         */
        if (rankMember.getCreateUserUid() != null) {
            R result = userFeignClient.getUserById(rankMember.getCreateUserUid());
            UserDto user;
            if(result.getCode()==0){
                user = result.getData(new TypeReference<UserDto>(){});
            }else {
                // 获取异常信息
                throw new FeignException("feign调用异常（根据用户id找用户）：失败");
            }

            StringBuilder text = new StringBuilder();
            text.append(String.format("您的稿件 %s ", rankMember.getMemberName()));
            if (AuditStatusEnum.REJECT.equals(rankMember.getAuditStatus())) {
                text.append("审核未通过，未通过原因：" + rankMember.getRejectReason());
                rabbitMqUtil.sendSimpleEmail(user.getEmail(), text.toString());
            } else if (AuditStatusEnum.AGREE.equals(rankMember.getAuditStatus())) {
                text.append("审核已通过");
                rabbitMqUtil.sendSimpleEmail(user.getEmail(), text.toString());
            } else {
                log.error("审核状态异常,稿件为{}", rankMember.getUid());
            }
            // 发送文章审核通过
            sendAuditNotice(rankMember, text.toString());
        }
        // 更新索引
        this.syncAggEsDoc(rankMember, OperateEnum.EDIT);
    }

    /**
     * 博客发布事件
     *
     * @param event
     */
    @EventListener(value = RankMemberPublishEvent.class)
    public void publish(RankMemberEvent event) {
        RankMemberEntity rankMember = (RankMemberEntity) event.getSource();

        /**
         * 站内信
         */
        this.sendNotice(rankMember);
        /**
         * 管理员发布
         */
        if (event.isAdmin()) {
            /**
             * 管理员下架的话
             */
            if (PublishEnum.NO_PUBLISH.equals(rankMember.getIsPublish())) {
                HttpServletRequest request = RequestHolder.getRequest();

                //  通过feign获取 admin.nickname
                String nickname;
                R adminResult = adminFeignClient.getAdminNicknameById(request.getAttribute(SysConf.ADMIN_UID).toString());
                if(adminResult.getCode()==0){
                    nickname = adminResult.getData(new TypeReference<String>(){});
                    // 将系统配置存入Redis中【设置过期时间24小时】
//                    redisUtil.setEx(RedisConf.SYSTEM_CONFIG, JsonUtils.objectToJson(systemConfig), 24, TimeUnit.HOURS);
                }else {
                    // 获取异常信息
                    throw new FeignException("feign调用异常（通过 id 获取管理员）：失败");
                }

                rankMember.setAuditName(nickname);
                rankMember.setAuditStatus(AuditStatusEnum.REJECT);
                rankMember.setRejectReason("管理员下架文章");
                rankMember.setAuditTime(new Date());

                R result = userFeignClient.getUserById(rankMember.getCreateUserUid());
                UserDto user;
                if(result.getCode()==0){
                    user = result.getData(new TypeReference<com.rede.didiok.common.dto.user.UserDto>(){});
                }else {
                    // 获取异常信息
                    throw new FeignException("feign调用异常（根据用户id找用户）：失败");
                }
//                UserDto user = userFeignClient.getUserById(rankMember.getCreateUserUid());
                StringBuilder text = new StringBuilder();
                text.append(String.format("<p>亲爱的的博主，您的博客稿件 %s 被管理员下架，如有疑问请联系管理员</p>", rankMember.getMemberName()));
                rabbitMqUtil.sendSimpleEmail(user.getEmail(), text.toString());

                // 发送站内信，文章被下架
                sendAuditNotice(rankMember, text.toString());

                return;
            }

        } else {
            /**
             * 用户发布
             */
            if (PublishEnum.PUBLISH.equals(rankMember.getIsPublish())) {
                /**
                 * 通知运营
                 */
                sendEmailToManager(rankMember);
            }
        }

        /**
         * 更新索引
         */
        this.syncAggEsDoc(rankMember, OperateEnum.EDIT);
    }

    /**
     * 博客删除事件
     *
     * @param event
     */
    @EventListener(value = RankMemberDeleteEvent.class)
    public void delete(RankMemberEvent event) {
        RankMemberEntity blog = (RankMemberEntity) event.getSource();

        /**
         * 更新索引
         */
        this.syncAggEsDoc(blog, OperateEnum.DELETE);
    }

    /**
     * 发送通知
     *
     * @param rankMember
     */
    public void sendNotice(RankMemberEntity rankMember) {
        /**
         * 上架操作
         */
        if (AuditStatusEnum.AGREE.equals(rankMember.getAuditStatus()) && PublishEnum.PUBLISH.equals(rankMember.getIsPublish())) {
            /**
             * 站内信通知
             */
            if (rankMember.getCreateUserUid() != null) {
                asyncService.executeAsyncBusinessNotice(false, rankMember.getCreateUserUid(), rankMember.getUid(), BusinessTypeEnum.RANK_MEMBER.getCode());
            } else {
                asyncService.executeAsyncBusinessNotice(true, rankMember.getAdminUid(), rankMember.getUid(), BusinessTypeEnum.RANK_MEMBER.getCode());
            }
        }
    }

    /**
     * 发送后台通知
     *
     * @param rankMember
     */
    public void sendBlackNotice(RankMemberEntity rankMember) {
        /**
         * 进入审批流程的博客 会给后台发送站内信通知
         */
        if (!AuditStatusEnum.AGREE.equals(rankMember.getAuditStatus()) || !PublishEnum.PUBLISH.equals(rankMember.getIsPublish())) {
            asyncService.executeAsyncBusinessBlackNotice(false, rankMember.getCreateUserUid(), rankMember.getUid(), BusinessTypeEnum.RANK_MEMBER.getCode(), rankMember.getMemberName());
        }

    }

    /**
     * 发送邮件通知
     *
     * @param rankMember
     */
    public void sendEmailToManager(RankMemberEntity rankMember) {
        /**
         * 发送邮件用纸
         */
        //  通过feign获取SystemConf
        SystemConfigDto systemConfig = systemConfigUtil.getSystemConfig();

        if (systemConfig != null && OpenStatusEnum.OPEN.equals(systemConfig.getStartEmailNotification())) {
            if (StringUtils.isNotEmpty(systemConfig.getEmail())) {
                log.info("发送邮件通知");
                String emailContent = "收到用户的投稿文章：" + rankMember.getMemberName();
                rabbitMqUtil.sendSimpleEmail(systemConfig.getEmail(), emailContent);
            } else {
                log.error("网站没有配置通知接收的邮箱地址！");
            }
        }
    }

    /**
     * 同步AggEsDoc
     *
     * @param rankMember
     * @return
     */
    private void syncAggEsDoc(RankMemberEntity rankMember, OperateEnum operate) {
        RankMemberDto rankMemberDto = new RankMemberDto();
        BeanUtils.copyProperties(rankMember,rankMemberDto);
        AggEsDoc aggEsDoc = AggEsDocConvert.convertRankMember(rankMemberDto);
        if (OperateEnum.ADD == operate && aggEsDoc.getOid() == null) {
            log.info("syncAggEsDoc: aggEsDoc oid is nil");
            RankMemberEntity blogTemp = rankMemberService.getById(rankMember.getUid());
            if (blogTemp != null) {
                aggEsDoc.setOid(blogTemp.getOid());
            }
            /**
             * 更新索引
             */
        }
        asyncService.executeAsyncUpdateEsAndRedis(aggEsDoc, operate);
    }

    /**
     * 差集(基于java8新特性)优化解法2 适用于大数据量
     * * 求List1中有的但是List2中没有的元素
     *
     * @param list1
     * @param list2
     * @return
     */
    public List<String> subList(List<String> list1, List<String> list2) {
        Map<String, String> tempMap = list2.parallelStream().collect(Collectors.toMap(Function.identity(), Function.identity(), (oldData, newData) -> newData));
        return list1.parallelStream().filter(str -> {
            return !tempMap.containsKey(str);
        }).collect(Collectors.toList());
    }

    /**
     * 发送审核通知
     *
     * @param rankMember
     * @param text
     */
    private void sendAuditNotice(RankMemberEntity rankMember, String text) {
        NoticeDto noticeDto = new NoticeDto();
        noticeDto.setCreateUserUid(rankMember.getCreateUserUid());
        noticeDto.setContent(text);
        noticeDto.setNoticeType(NoticeTypeEnum.SYSTEM.getCode());
        noticeDto.setBusinessType(BusinessTypeEnum.RANK_MEMBER_AUDIT.getCode());
        noticeDto.setBusinessUid(rankMember.getUid());
        noticeDto.setIsBack(Constants.NUM_ZERO);
        asyncService.executeAsyncBusinessNotice(noticeDto);
    }

}
